<?php

/**
 * Erra_System_Factory - Field factory
 *
 * @package
 * @author Alexis Eric
 * @copyright Copyright (c) 2012 - Erra Prod
 * @version $1.0$
 * @access public
 */
class Erra_System_Factory {

    public static $adminFields = array();

    /**
     * Erra_System_Factory::getFieldObject() - Returns an object from factory
     *
     * @param mixed $object_classname - The id of the field in factory (the classname of the object)
     * @param mixed $object_id - The unique id for this object
     * @param mixed $flags - SESSION|SQL|CREATE, tells method to build the field
     * @param mixed $WHERE_CLAUSE - an optional SQL clause if you want to extract field from database
     * @param mixed $buildArgs - The arguments needed to build field
     * @return
     */
    public static function getFieldObject($object_class, $object_id, $flags = null, $WHERE_CLAUSE = null, $buildArgs = null) {
        $field = self::createField($object_class, $object_id, $buildArgs);
        if (config_get('database.synchronize_schema') == 1) {
            Erra_Persistance_SqlTable::synchronize($field);
        }
        // Generate random identifier if field has no specific name
        // TODO : randomize more
        $object_id = !strlen($object_id) ? $object_class . '_' . uniqid() : $object_id;
        $field->setObjectId($object_id);
        $field->setName($object_id);
        $flags_str = $flags;

        if (!is_null($field) && is_object($field)) {
            $flags = explode('|', $flags);
            foreach ($flags as $containerName) {
                // fetching object from $_SESSION ?
                if (strtolower($containerName) == 'session') {
                    $uniqueNeedle = $field->getObjectClass() . '.' . $field->getObjectId();
                    $fieldResult = Erra_Persistance_Session::get($uniqueNeedle);
                    // Fetch object from SQL ?
                } else if (strtolower($containerName) == 'sql') {
                    $fieldResult = Erra_Persistance_PersistanceUnit::getFieldFromSQL($field, $WHERE_CLAUSE);
                    // We want to create object
                } else if (strtolower($containerName) == 'create') {
                    $fieldResult = $field;
                }
                if (!is_null($fieldResult) && is_object($fieldResult)) {
                    // Internal flag to avoid storage when field is read from object
                    return $fieldResult;
                }
            }
        }
        return null;
    }

    /**
     * Erra_System_Factory::createField() - Creates a field
     *
     * @param mixed $object_class
     * @param mixed $WHERE_CLAUSE
     * @param mixed $buildArgs
     * @return
     */
    public static function createField($object_class, $object_id, $buildArgs = null) {
        if (class_exists($object_class)) {
            return new $object_class($object_id, $buildArgs);
        }
        Erra_Core_Kernel::log('[Erra_System_Factory::createField] : La classe \'' . $object_class . '\' est inexistante !');
        return null;
    }

    /**
     * Erra_System_Factory::saveField() - Saves field in the right container
     *
     * @param mixed $field
     * @param mixed $flags
     * @return
     */
    public static function saveField($field, $flags) {
        $flags = strtoupper($flags);
        $flags = explode('|', $flags);
        if (is_array($flags) && in_array('SESSION', $flags)) {
            $uniqueNeedle = $field->getObjectClass() . '.' . $field->getObjectId();
            Erra_Persistance_Session::set($uniqueNeedle, $field);
        }
        if (is_array($flags) && in_array('SQL', $flags)) {
            Erra_Persistance_PersistanceUnit::saveField($field);
        }
        if (!is_array($flags) || !in_array('SQL', $flags) && !in_array('SESSION', $flags)) {
            Erra_Core_Kernel::log('Erra_System_Factory::saveField(' . $field->getObjectId() . ') had no effect, the $flags variable \'' . $flags . '\' is not persistant');
        }
    }

    /**
     * Erra_System_Factory::getFieldList()  Automatically generates an array of fields with given parameters
     *
     * @param mixed $objectName
     * @param mixed $WHERE_CLAUSE
     * @param mixed $buildArgs
     * @return
     */
    public static function getFieldList($object_class, $WHERE_CLAUSE = null, $buildArgs = null, $ALL = null) {
        $ALL = ($ALL == 'ALL') ? true : false;
        $object = self::createField($object_class, $object_class, $buildArgs);
        if (config_get('database.synchronize_schema') == 1) {
            Erra_Persistance_SqlTable::synchronize($object);
        }
        $tableName = $object->getTableName();
        $request = 'SELECT id, object_id, object_class ';
        $countRequest = 'SELECT COUNT(id) as realItemCount ';
        foreach ($object->getSubFields() as $aSubField) {
            if ($aSubField->isInAdminList() == true) {
                $request .= ', ' . $aSubField->getObjectId();
            }
        }

        $request .= ' FROM ' . $tableName . ' ';
        $countRequest .= ' FROM ' . $tableName . ' ';

        // ADD SEARCH CRITERIA
        $sqlCriteria = array();
        $paginator = array();
        $AND_CLAUSES = array();
        if (isset($_SESSION['search__'][$object_class])) {
            $searchArray = $_SESSION['search__'][$object_class];

            foreach ($searchArray as $fieldName => $searchValue) {
                if (isset($searchValue['operator']) && isset($searchValue['criteria']) && strlen($searchValue['criteria'])) {
                    if ($fieldName == 'paginator__realItemCount') {
                        // Do something ?
                    } else if (strstr($fieldName, 'paginator__')) {
                        // Its a paginator element
                        $paginatorFieldName = str_replace('paginator__', '', $fieldName);
                        $paginator[$paginatorFieldName] = $searchValue['criteria'];
                    } else {
                        // Standard parameter
                        if (!stristr($searchValue['operator'], 'limit ') && $searchValue['criteria'] != '_') {
                            // TODO : better SQL syntax
                            $criteriaList = is_array($searchValue['criteria']) ? $searchValue['criteria'] : array($searchValue['criteria']);
                            $safeQuery = '';
                            foreach ($criteriaList as $criteria) {
                                // Secure input item
                                $safeItem = addslashes($criteria);
                                $queryCharacters = array('?', '%');
                                $queryReplace = array('', '');
                                $safeItem = str_replace($queryCharacters, $queryReplace, $safeItem);
                                // Rebuild query
                                $queryPattern = array('%?%', '%?', '?%', '?');
                                $queryReplace = array('"%' . $safeItem . '%"', '"%' . $safeItem . '"', '"' . $safeItem . '%"', '"' . $safeItem . '"');
                                $safeQuery .= (empty($safeQuery)) ? $safeQuery : ' OR ';
                                $safeQuery .= str_replace($queryPattern, $queryReplace, $fieldName . ' ' . $searchValue['operator']);
                            }
                            $AND_CLAUSES[] = $safeQuery;
                        }
                    }
                }
            }
        }


        // Rebuilt where clause if we don't request the whole list
        if (!$ALL) {
            $FINAL_WHERE = $WHERE_CLAUSE;
            foreach ($AND_CLAUSES as  $AND_CLAUSE) {
                $FINAL_WHERE .= (is_null($FINAL_WHERE)) ? ' WHERE ' . $AND_CLAUSE : ' AND ' . $AND_CLAUSE;
            }
            $request .= $FINAL_WHERE;
            $countRequest .= $FINAL_WHERE;
        }

        $countRes = Erra_Core_DatabasePdo::_SELECT($countRequest);

        /* ORDER BY */
        if (isset($_POST[$object_class]['order_by']) && strlen($_POST[$object_class]['order_by'])) {
            // TODO : sanitize 
            $request .= ' ORDER BY ' . $_POST[$object_class]['order_by'] . ' ';
        }
        // Always set a column to sort data
        if (!strstr($request, 'ORDER BY')) {
            $request .= 'ORDER BY id DESC';
        }

        $realItemCount = 0;
        if (Erra_Core_DatabasePdo::rowCount() > 0) {
            $result = $countRes->fetch();
            $realItemCount = $result['realItemCount'];
        }
        Erra_Fields_Search_PageNumber::$realItemCount[$object_class] = $realItemCount;

        // Set correct Limit
        if (count($paginator) != 2 || !isset($paginator['pageSize']) || !isset($paginator['pageNumber']) || !is_numeric($paginator['pageSize']) || !is_numeric($paginator['pageNumber']) || $paginator['pageSize'] < 1 || $paginator['pageNumber'] < 1) {
            $paginator = array('pageSize' => Erra_Fields_Search_PageSize::$defaultPageSize, 'pageNumber' => 1);
        }
        $pageNumber = $paginator['pageNumber'] - 1;
        $pageSize = $paginator['pageSize'];
        if (!$ALL) {
            // Avoid unauthorized operations
            if ($pageNumber * $pageSize > $realItemCount) {
                $pageNumber = 1;
                $request .= ' LIMIT 0, ' . $pageSize;
            } else {
                $request .= ' LIMIT ' . ($pageNumber * $pageSize) . ', ' . $pageSize;
            }
        }

        $qres = Erra_Core_DatabasePdo::_SELECT($request);

        $result = array();
        if (is_object($qres)) {
            while ($row = $qres->fetch()) {
                $row = Erra_Utils_Tools::arrayFilterStringKeys($row);
                if ($row['object_class'] != $object_class) {
                    Erra_Core_Kernel::log('Erra_System_Factory::getFieldList() - Problème de résolution interne de noms, la classe appelée (' . $object_class . ') ne correspond pas aux informations présentes en base (' . $row['object_class'] . ')');
                }
                // We don't want any null value in our table
                foreach ($row as $key => &$value) {
                    if (is_null($value)) {
                        $value = '';
                    }
                }
                // Create Unique object
                $result[] = $row;
            }
        } else {
            // Set a default element to force array render
            $result[] = array();
        }
        // Set previous/next id
        for ($i = 0; $i < count($result); $i++) {
            if (count($result) > ($i + 1)) {
                $nextId = $result[$i + 1]['id'];
                $result[$i]['nextId'] = $nextId;
            }
            if (($i - 1) >= 0) {
                $prevId = $result[$i - 1]['id'];
                $result[$i]['prevId'] = $prevId;
            }
        }
        // Last items first
       // $result = array_reverse($result);
        $field_array = new $object_class($object_class, $buildArgs);
        $field_array->setObjectDataArray($result);
        $field_array->setObjectId($object_class);
        $field_array->setFetchFromList(true);
        $field_array->_postListInit();
        return $field_array;
    }

}

?>